<?php
namespace Models;

use Libraries\WxPayApi;
use Models\Common\MoneyLogTrait;
use GuzzleHttp\Client;

/**
 * 订单模型
 * @package Models
 * @author 江羿平<hugcolin@163.com>
 */
class Order extends Model{

	use MoneyLogTrait;

	protected $_table = 'orders';

	protected $_primekey = 'id';

	protected $_has_many = [
		'order_refund' => [
			'class' => OrderRefund::Class,
			'foreign' => 'order_id',
		]
	];

	protected $_belongs = [
		'address' => [
			'class' => Address::Class,
			'foreign' => 'id',
			'belongs_key' => 'address_id'
		],
		'user' => [
			'class' => User::Class,
			'foreign' => 'id',
			'belongs_key' => 'user_id'
		]
	];

	public $error = null;

	public $error_info = array();

	public function __construct(){
		parent::__construct();
		$this->error_info = CONFIG('basic.order_errors');
	}

	public function filter($data){
		if (isset($data['status']))
			$data['status_text'] = get_order_status($data['status']);
		return $data;
	}

	/**
	 * 生成订单
	 * @param  $arr   商品规格和数量数组，格式：[[item_id=>1,qty=>5]]
	 * @param  $user_id 用户ID
	 * @param  $options 其他参数
	 * @return $order|false 订单或失败
	 */
	public function create($arr,$user_id,$options=array()){
		$item = new Item;
		$item_ids = array();
		foreach ($arr as $it) {
			$item_ids[] = $it['item_id'];
		}
		$items = $item->default_filter(false)->where_in('id',$item_ids)->get();

		$arr = arr_key($arr,'item_id');

		$order_items = array();
		$data['total'] = 0;
		$weight = 0;
		$vat = 0;
		foreach ($items as $k=>$ite) {
			$qty = $arr[$ite['id']]['qty'];
			if(!isset($options['type']) || $options['type'] != 1){
				//线上订单判断商品库存
				if($ite['stock'] < $qty){
					$this->error = 1; //有商品库存不足
					return FALSE;
				}
				if($ite['is_delete'] == 1 ){
					$this->error = 3; //商品已经下架
					return FALSE;
				}
			}

			//获取单价
			$price = $ite['price'];

			$order_item = array(
				'product_id'=>$ite['product_id'],
				'item_id'=>$ite['id'],
				'qty'=>$qty,
				'price'=>$price,
				'total'=>$price*$qty,
				'status'=>0
			);

			$order_items[] = $order_item;
			$data['total'] += $price*$qty; //订单总价
			$weight += $qty*$ite['weight']; //商品总重量
			$vat += $qty*$ite['tax'];
		}

		//线上订单，查找用户默认地址
		// if(!isset($options['type']) || $options['type'] == 1){
		// 	$address = new Address;
		// 	$address = $address->where('user_id',$user_id)->order_by('is_default','desc')->get_one();
		// }

		//优惠金额
		if($user_id){
			$user = (new User)->find($user_id);
			if($user){
				$level = (new UserLevel)->find($user['level']);
				if($level){
					if(!isset($options['cut_fee'])){
						$data['cut_fee'] = $data['total'] - $data['total']*$level['discount'];
					}
					$data['discount'] = $level['discount'];
				}
			}
		}


		//存储订单
		$data = array_merge($data,$options);
		$data['order_id'] = date('YmdHis').$user_id.rand(100000,999999);
		$data['user_id'] = $user_id;
		$data['address_id'] = isset($address) ? $address['id'] : 0;
		$data['weight'] = $weight;
		$data['vat'] = $vat;
		if(isset($options['cashier_id']) && $options['cashier_id']>0){
			$data['shipping_fee'] = 0;
		}else{
			//运费
			$data['shipping_fee'] = $this->shipping($user_id,$data['total'],$data['address_id']);
		}
		// $CREDITS_PERCENT = config('sys.CREDITS_PERCENT');
		// $data['credits'] = $data['total']*($CREDITS_PERCENT/100); //返积分
		$data['create_time'] = date('Y-m-d H:i:s');
		$order_id = $this->add($data);
		if(!$order_id){
			$this->error = 2;
			return FALSE;
		}

		//添加到订单商品表
		$order_item = new Order_item;
		foreach ($order_items as $o) {
			$o['order_id'] = $order_id;
			$o['user_id'] = $user_id;
			$order_item->add($o);
		}

		return $this->find($order_id);
	}

	/**
	 * 计算运费
	 * @param   $user_id    用户ID
	 * @param   $total_fee     重量
	 * @param   $address_id 收货地址
	 * @return  int 运费
	 */
	public function shipping($user_id,$total_fee,$address_id = 0){

		return $total_fee >= 10 ? 0 : 1;
	}

	/**
	 * 支付订单
	 * @param  $order      订单
	 * @param  $money_pay     是否启用了余额支付
	 * @param  $pay_mode      其他支付方式
	 * @param  $pay_fee       其他支付的金额
	 * @param  $pay_no        第三方支付交易号
	 */
	public function payed($order,$money_pay=0,$pay_mode=0,$pay_fee =0,$pay_no=''){

		if($order['user_id']){
			$user = new User;
			$user = $user->find($order['user_id']);

			if(!$user) {
				$money_pay = 0;
			}
		}else{
			$money_pay = 0;
		}

		if(!$money_pay && !$pay_mode){
			return array('code'=>1);
		}

		$fee = $order['total'] - $order['cut_fee'] + $order['shipping_fee'];

		$money = 0; //余额需要支付的金额

		if($money_pay){
			$money = min($user['balance'],$fee);
		}

		$pay_money = $fee - $money;

		if (sprintf('%.2f', $fee) > sprintf('%.2f', $money+$pay_fee)) {
			return array('code'=>2);
		}

		if($money > 0){
			$data['pay_mode'] = 0; //余额支付
			$data['money'] = $money;

			//减少用户余额，添加用户总消费金额
			$user_data['balance'] = $user['balance'] - $money;
			$user_data['total_money'] = $user['total_money'] + $fee;
			$user->update($user['id'],$user_data);
		}

		//使用第三方支付
		if ($pay_fee > 0) {
			$data['pay_fee'] = $pay_fee;
			$data['pay_no'] = $pay_no;
			$data['pay_mode'] = $pay_mode;
		}

		$data['status'] = $order['type']==1?3:1;
		$data['money'] = $money;
		$data['last'] = floatval(isset($user) ? $user['balance'] : 0);
		$data['now'] = $data['last'] - $money;
		$data['pay_time'] = date('Y-m-d H:i:s');
		$this->update($order['id'],$data);

		//修改库存
		$this->stock($order['id']);

		//加入余额记录
		$order = $order->find($order['id']);
		$money_log_data = [
			'last' => floatval(isset($user) ? $user['balance'] : 0),
			'now' => floatval(isset($user) ? $user['balance'] - $money : 0),
		];
		if ($money > 0) {
			$order->saveMoneylog(array_merge($money_log_data, [
				'num' => -$money,
				'desc' => "订单{$order['id']} 余额支付部分 {$money} 元",
				'pay_type' => 0
			]));
		}
		if ($pay_fee > 0) {
			$pay_types = config('basic.pay_types');
			$order->saveMoneylog(array_merge($money_log_data, [
				'num' => $pay_fee,
				'last' => floatval(isset($user) ? $user['balance'] - $money : 0),
				'desc' => "订单{$order['id']} {$pay_types[$pay_mode]['chinese']}支付部分 {$pay_fee} 元",
				'pay_type' => $pay_mode
			]));
		}

		// 向收银端推送通知
		if (!$order['cashier_id']) {
			$client = new Client();
			$response = $client->request('post', "http://127.0.0.1:4237/server/notification/orderCreated/{$order['id']}", [
				'form_params' => [
					'request' => ''
				]
			]);
			if ($response->getStatusCode() != 200) {
				log_message('error', '发送订单推送失败', (string) $response->getBody());
			}
		}

		return TRUE;
	}

	/**
	 * 修改商品数量和库存
	 * @param  int $order_id 订单id
	 * @return void
	 */
	private function stock($order_id){
		$items = Order_item::where('order_id', $this['id'])->with('item','id,stock,solded,danger_stock')->get();
		$product_ids = array();

		$stocks = ['field'=>'stock','key'=>'id','data'=>[]];
		$soldeds = ['field'=>'solded','key'=>'id','data'=>[]];
		$item_ids = array();

		foreach ($items as $itm) {
			if(!in_array($itm['product_id'], $product_ids)){
				$product_ids[] = $itm['product_id'];
			}
			$item_ids[] = $itm['item_id'];

			$qty = $itm['qty'];
			$stocks['data'][$itm['item_id']] = $itm['item']['stock'] - $qty;
			$soldeds['data'][$itm['item_id']] = $itm['item']['solded'] + $qty;

		}

		//修改Item库存和销量
		$where = 'id in ('.implode(',', $item_ids).')';
		(new Item)->multi_update([$stocks,$soldeds],$where);

		//修改商品库存和销量
		(new Product)->stock($product_ids);
	}

	/**
	 * 修改进货记录中库存数量
	 */
	public function purchaseRecordStock($order_id){
		$items = Order_item::where('order_id', $this['id'])->get();
		$item_ids = [];
		foreach ($items as $itm) {
			$item_ids[] = $itm['item_id'];
		}

		$pr = new PurchaseRecord;
		$prs = $pr->where_in('item_id',$item_ids)->where('stock>',0)->order_by('expire','asc')->get();
		$stocks = ['field'=>'stock','key'=>'id','data'=>[]];
		$pr_ids = [];
		foreach ($items as $itm) {
			$qty = $itm['qty'];
			foreach ($prs as $p) {
				if($itm['item_id'] == $p['item_id']){
					$pr_ids[] = $p['id'];
					if($qty <= $p['stock']){
						$stocks['data'][$p['id']] = $p['stock'] - $qty;
						break;
					}else{
						$stocks['data'][$p['id']] = 0;
						$qty = $qty - $p['stock'];
					}
				}
			}
		}

		if ($pr_ids) {
			$where = 'id in ('.implode(',', $pr_ids).')';
			(new PurchaseRecord)->multi_update([$stocks],$where);
		}
	}


	// 获取订单商品信息
	public function items()
	{
		$items = Order_item::where('order_id', $this['id'])
			->with(['product', 'item'])
			->get();
		return $items;
	}

	public function shipping_type()
	{
		$expresses = CONFIG('basic.expresses');

		return isset($expresses[$this['shipping_type']]) ? $expresses[$this['shipping_type']] : '';
	}

	public function address()
	{
		$address = (new Address)->find($this['address_id']);

		return $address;
	}

	public function cashier()
	{
		$cashier = (new Cashier)->find($this['cashier_id']);

		return $cashier;
	}

	public function refunds()
	{
		$refunds = Refund::where('order_id', $this['id'])->with(['product', 'item'])
		->get();

		return $refunds;
	}

	public function order_refunds()
	{
		$order_refunds = OrderRefund::where('order_id', $this['id'])->with(['refunds' => function ($query) {
			$query->with(['product', 'item']);
		}])->get();

		return $order_refunds;
	}

	/** {@inheritDoc} */
	public function getMoneyType()
	{
		return $this['type'];
	}

	public function getMoneyLogData($data)
	{
		return [
            'type' => $this->getMoneyType(),
            'user_id' => $this['user_id'],
            'cashier_id' => $this['cashier_id'],
            'relation_id' => $this['id'],
            'num' => $data['num'],
            'last' => isset($data['last']) ? $data['last'] : '',
            'now' => isset($data['now']) ? $data['now'] : '',
            'desc' => isset($data['desc']) ? $data['desc'] : '',
            'pay_type' => isset($data['pay_type']) ? $data['pay_type'] : '',
            'from' => isset($data['from']) ? $data['from'] : '',
            'create_time' => date('Y-m-d H:i:s')
        ];
	}
}
?>
